package edu.sjsu.cs.queryopt.dbms.main;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;

public class MatchCol {
	static WordCapsule wc = new WordCapsule();
	static AccessTypeOne ato = new AccessTypeOne();
	static String bestmatching   = "";

	/**
	 * 
	 * Checking How many matching col is in the one index
	 * 
	 * EX) Index (1, 3) Query (1,3)  ->2
	 *     Index (1 , 3) Query(1) ->1
	 *     Index (1 , 3) Query (1, 4) - > 1
	 * */
	
	public String HowManyMatchColIsInOneIndex(ArrayList<String> oneRow , ArrayList<String> htRow){
		int tracker = 0;
		int index = 0 ;
		while((oneRow.size() != index) && (htRow.size() != index)){
			String one = oneRow.get(index).trim();
			String two  = htRow.get(index).trim();
			if(one.equals(two)){
				tracker++;
			}
			index++;
		}
//		System.out.println("Tracker " +  tracker);
		return Integer.toString(tracker);
		
	}
	
	public String getNameForHostMatchCol (ArrayList<String> conditionpod ,
			Hashtable<String, ArrayList<String>> ht ,ArrayList<String> newSet )
	{
		Hashtable<String, ArrayList<String>>map =  reOrderIndex(conditionpod , ht, newSet);
		int tracker = 0 ;
		String name = "";
//		System.out.println("map in getName " +  map);
		/**
		 * get high value first 
		 * */
		int highVal = 0 ;
		for(int index = 0 ; index < newSet.size() ; index++){
			if(highVal < map.get(newSet.get(index)).size()){
				
				highVal = map.get(newSet.get(index)).size();
			}
		}
		
		
		for(int i = 0 ;  i < newSet.size() ; i++)
		{
			if(highVal == map.get(newSet.get(i)).size()){
				name = newSet.get(i);
				break;
			}
			
		}
//		System.out.println("nam:e " + name);
		bestmatching = name;
		return name;
	}
	
	/**
	 * get the high value for match col
	 * 
	 * */
	public String GetMatchColForNoTIe(ArrayList<String> conditionpod ,
			Hashtable<String, ArrayList<String>> ht ,ArrayList<String> newSet )
	{
		Hashtable<String, ArrayList<String>>map =  reOrderIndex(conditionpod , ht, newSet);
//		System.out.println("mapmapmap  GetMatchColForNoTIe" + map);
		int tracker = 0 ;
		/**
		 * get high value first 
		 * */
		int highVal = 0 ;
		for(int index = 0 ; index < newSet.size() ; index++){
			if(highVal < map.get(newSet.get(index)).size()){
				
				highVal = map.get(newSet.get(index)).size();
			}
		}

//		System.out.println("highVal " + highVal);
		
		return Integer.toString(highVal);
		
	}
	
	/**
	 * 
	 * if it is not tie then returning the highest value index
	 * 
	 * */
	
	public String isNotTie(Hashtable<String, Integer> htc  , ArrayList<String> newSet
			){
//		System.out.println("htc isnot " + htc);
//		System.out.println("newSet isnot " + DBMS.PlanTable);
		
		int maxval = Collections.max(htc.values());
		if(maxval >0 ){
		for(int index = 0 ; index < newSet.size() ; index++){
			if(maxval == htc.get(newSet.get(index))){
				
				return newSet.get(index);
			}
		}
		}
		
		return "max value is 0";
		
		
	}

	/***
	 * 
	 * Find the if there more than one high value list
	 * if more than two high value  list then it is matching
	 * 
	 * */
	public boolean ISTIE (ArrayList<String> conditionpod ,
			Hashtable<String, ArrayList<String>> ht ,ArrayList<String> newSet )
	{
		Hashtable<String, ArrayList<String>>map =  reOrderIndex(conditionpod , ht, newSet);
		int tracker = 0 ;
		
		/**
		 * get high value first 
		 * */
		int highVal = 0 ;
		for(int index = 0 ; index < newSet.size() ; index++){
			if(highVal < map.get(newSet.get(index)).size()){
				
				highVal = map.get(newSet.get(index)).size();
			}
		}
//		System.out.println("HIGH VALUE " +highVal );
		
		for(int i = 0 ;  i < newSet.size() ; i++)
		{
			if(highVal == map.get(newSet.get(i)).size()){
				tracker++;
			}
			
		}
//		System.out.println("TRACKER " + tracker);
		return (tracker > 1)? true : false;
	}


	
	
	public  Hashtable<String, ArrayList<String>> reOrderIndex(ArrayList<String> conditionpod ,
			Hashtable<String, ArrayList<String>> ht ,ArrayList<String> newSet )
	{
//		System.out.println("conditionpod reOrderIndex" + conditionpod);
//		System.out.println("ht " + ht);
//		System.out.println("newSet " + newSet);
		 // NEED : getAllIndexesFromOneRow
		 //        getRidOfA
		 /**
		  * First , get map [1A, 2A, 3A] -> [ 1, 2, 3]
		  * */
		Hashtable<String, ArrayList<String>> newht = new Hashtable<String, ArrayList<String>> ();
		Hashtable<String, ArrayList<String>> bestnewht = new Hashtable<String, ArrayList<String>> ();
		
		for(int index = 0 ; index < newSet.size() ; index++){
			ArrayList<String> put = ato.getRidOfA(ht.get(newSet.get(index)));
			newht.put(newSet.get(index), put);
			put = new ArrayList();
		}
//		System.out.println(" put IN " + newht);
		ArrayList<String> map = isRangeOrNotInPredicate(conditionpod);
//		System.out.println("map reOrderIndex" + map);
		for(int i = 0 ; i < newht.size() ; i++){
			ArrayList<String> newMapper = reMappingIndexListForMatchingCol(newht.get(newSet.get(i)) , map , newSet.get(i));
			bestnewht.put(newSet.get(i), newMapper);
			
			
		}
		
//		System.out.println("bestnewht " + bestnewht);
		return bestnewht;
	}
	/**
	 * Using map to find the matching col
	 * 
	 * 
	 * */
	public ArrayList<String> reMappingIndexListForMatchingCol(ArrayList<String> map
			, ArrayList<String> OrignalMap , String tbname){
//		System.out.println("fucking map " + map);
//		System.out.println("fucking OrignalMap " + OrignalMap);
//		System.out.println("fucking tbname " + ato.tableNumberFromTable(ato.getTableNameFromIndex(tbname)));
		/**
		 * We need maptbname because we need to check wheter we can use for map
		 * becaust t1.1  and t2.1 is different
		 * */
		String maptbname =  ato.tableNumberFromTable(ato.getTableNameFromIndex(tbname));
//		System.out.println("maptbnamemaptbname " + maptbname);
		ArrayList<String> re = new ArrayList<String>();
		

		int flag = 0;
		for(int index = 0 ; index < map.size() ; index++){
			
			for(int inner = 0 ; inner < OrignalMap.size() ; inner++){
				String calname = OrignalMap.get(inner).substring((OrignalMap.get(inner).length()-1));
//				System.out.println("calname " + calname);
//				System.out.println("ap.get(index) " + map.get(index));
//				System.out.println("OrignalMap.get(inner).charAt(1) " +OrignalMap.get(inner).charAt(1));
				if(maptbname.trim().charAt(0) == OrignalMap.get(inner).charAt(0) && map.get(index).trim().equals(calname.trim()) && OrignalMap.get(inner).charAt(1) == 'Y'){
//					System.out.println("THIS IS RANGE BREAK");
					re.add(map.get(index));
					flag = 1;
					break;
				}
				if(maptbname.trim().charAt(0) == OrignalMap.get(inner).charAt(0) && map.get(index).trim().equals(calname.trim()) && OrignalMap.get(inner).charAt(1) == 'N'){
//					System.out.println("THIS IS NOT RANGE BREAK");
					re.add(map.get(index));
					
				}
				else{
//					System.out.println("NOT MATCHING DONE");
					
				}
			}
			if(flag == 1){
				break;
			}
			
			
		}
		
//		System.out.println("rerere " + re);
		return re;
		
	}
	
	/**
	 * READ T2.1 = 100 AND T2.2 > 10 AND T2.3 = 1
	 * THEN RETURN  [ N ,Y ,N]
	 * */
	public ArrayList<String> isRangeOrNotInPredicate(ArrayList<String> conditionpod){
		ArrayList<String> Map = new ArrayList<String>();
//		System.out.println("conditionpod  conditionpod" + conditionpod);
		for(int index = 0 ; index < conditionpod.size() ; index++){
			if(conditionpod.get(index).trim().equals("=") || conditionpod.get(index).trim().equals("IN")){
				String tbnum = ato.tableNumberFromTable(ato.getTableName(conditionpod.get(index-1).trim()));
				String colnum = ato.getColNumer((conditionpod.get(index-1).trim()));
				Map.add(tbnum+"N"+colnum );
				String joinhelper = conditionpod.get(index-1) + " " + "=" + " " +conditionpod.get(index+1);
				if(ato.isJoinPredicateForString(joinhelper)){
					tbnum = ato.tableNumberFromTable(ato.getTableName(conditionpod.get(index+1).trim()));
					colnum = ato.getColNumer((conditionpod.get(index+1).trim()));
					Map.add(tbnum+"N"+colnum );
				}
				
			}
			if(conditionpod.get(index).trim().equals(">") ||
					conditionpod.get(index).trim().equals("<")){
				String tbnum = ato.tableNumberFromTable(ato.getTableName(conditionpod.get(index-1).trim()));
				String colnum = ato.getColNumer((conditionpod.get(index-1).trim()));
				Map.add(tbnum+"Y"+colnum);
				
			}
		}
//		System.out.println("MapMapMap " + Map);
		return Map;
	}
	
	public String isNotTieTwo(Hashtable<String, Integer> htc  , ArrayList<String> newSet ,
			Hashtable<String, Integer>afterfindit){
//		System.out.println("htc isnot " + htc);
//		System.out.println("newSet isnot " + newSet);
//		System.out.println("afterfindit isnot " + afterfindit);
		int maxval = Collections.max(afterfindit.values());
		ArrayList<String> notTieSet = new ArrayList<String>();
		
		if(maxval >0 ){
		for(int index = 0 ; index < newSet.size() ; index++){
			if(maxval == afterfindit.get(newSet.get(index))){
				notTieSet.add(newSet.get(index));
				
				}
			}
		}
		
		return "max value is 0";
		
		
	}
	
	/**
	 * Checking if there is Tie matching value indexes or not
	 * 
	 * @return true: if there is more than two tie max value indexes;
	 * 		 false : otherwise.
	 * 
	 * */
	
	
	public boolean isTie (Hashtable<String, Integer> afterfindit , ArrayList<String> newSet , Hashtable <String, Integer> htc){
		int tracker = 0 ;
		
		/**
		 * get high value 
		 * */

//		 System.out.println("afterfindit " + afterfindit);
//		 System.out.println("newSet isTie " + newSet);
//		 System.out.println("htc " + htc);

		 
		 
		 int high = Collections.max(htc.values());
		for(int index = 0 ; index < newSet.size() ; index++){
			int sum = htc.get(newSet.get(index));
			if(high == sum){
				tracker++;
			}
			
		}
		
		return (tracker >  1)? true : false;
	}
	/**
	 * when predicate is tie return tie value
	 * 
	 * */
	public String getTieVale (ArrayList<String> conditionpod ,
			Hashtable<String, ArrayList<String>> ht ,ArrayList<String> newSet ){
		
		Hashtable<String, ArrayList<String>>map =  reOrderIndex(conditionpod , ht, newSet);
//		System.out.println("mapmapmap " + map);
		int tracker = 0 ;
		
		/**
		 * get high value first 
		 * */
		int highVal = 0 ;
		for(int index = 0 ; index < newSet.size() ; index++){
			if(highVal < map.get(newSet.get(index)).size()){
				
				highVal = map.get(newSet.get(index)).size();
			}
		}
	
		 return Integer.toString(highVal);
		
	}


	
	/**
	 * After get normailzed predicate and indexes
	 * Find the matching col again FUCK YOU
	 * 
	 * 
	 * 
	 * */
	public Hashtable<String, Integer> findNewMatchingCol(
			ArrayList<String>conditionpod ,
			Hashtable<String, ArrayList<String>> matchinght ,
			ArrayList<String> newSet ) {
//		System.out.println("conditionpod  findNewMatchingCol " + conditionpod);
//		System.out.println("matchinght " + matchinght);
//		System.out.println("newSet " + newSet);
		Hashtable<String, Integer> reht = new Hashtable<String,Integer>();
		int tracker = 0 ;
		
		ArrayList<String> tablename = new ArrayList<String>();
		
		for(int i = 0 ; i < conditionpod.size() ; i++)
		{
			if(conditionpod.get(i).startsWith("T")){
				tablename.add(conditionpod.get(i));
			}
		}
		
//		System.out.println ("tablename " + tablename);
		for(int index = 0 ; index < newSet.size() ; index++){
			ArrayList<String> al =  matchinght.get(newSet.get(index));
//			System.out.println("newSet.get(index) " + newSet.get(index));
			for(int i = 0 ; i < tablename.size() ; i++){
				String number = ato.getColNumer(tablename.get(i));
				if(newSet.get(index).startsWith(ato.getTableName((tablename.get(i)))))
				{
					if(ato.IsIntheList(al, number)){
						tracker++;
					}
				}

			}
			if(tracker > 0){
			reht.put(newSet.get(index), tracker);
			}
			tracker=0;
			
		}
//		System.out.println("reht "+ reht);
		
		return reht;
	}
	
	/**
	 * 1. from condidtion list need to handle two cases
	 * 		case1: read everything if there is not range predicate  "<" or ">"
	 * 	    -> if there is range then do not read after that
	 * 		case2: read everything until end
	 * 
	 * @param ArrayList<String> : After where part
	 * 
	 * @return ArrayList<String> : PotentialCo
	 * 
	 * */
	 ArrayList<String> GetPotentialCol(ArrayList<String> condition){
		
//		System.out.println("/***MATCH***/");
		
		ArrayList<String> re = new ArrayList<String>();
		for(int index = 0; index < condition.size() ; index++){
			if(wc.QWC_GT.equals(condition.get(index).trim())
					|| wc.QWC_LS.equals(condition.get(index).trim())){
				break;
			}
			if(condition.get(index).trim().startsWith("T")){
				re.add(condition.get(index).trim());
			}
			
		}
		
		return re;
	}
	 /**
	  * RULE: 1. First col is always matching.
	  * RULE: 2. If it is increasing ssequentially it is matching 
	  * 		o/w it is not 
	  * CREATE INDEX X1 ON T1 ( 1A , 3A )  -> 1
	  *	CREATE INDEX X2 ON T1 ( 4A , 5A , 2A ) -> 4 , 5
	  *	CREATE INDEX X3 ON T1 ( 3A ) -> 3
	  * 
	  * @param Hashtable<String, ArrayList<String>> ht indexlists
	  * @param ArrayList<String> keyset
	  * 
	  * @return Hashtable<String, ArrayList<String>> new List of matching
	  * */
	Hashtable<String, ArrayList<String>> getMatchingColInIndexs(
			Hashtable<String, ArrayList<String>> ht ,
			ArrayList<String> keyset ){
//		System.out.println("/***getMatchingColInIndexs***/");
		
		Hashtable<String, ArrayList<String>> newht = new Hashtable<String, ArrayList<String>>();
		ArrayList<String> newal = new ArrayList<String>();
		for(int index = 0; index < keyset.size() ; index++){
			ArrayList<String> al = ht.get(keyset.get(index));
			
			int remember = 99999;
			for(int i = 0 ;  i < al.size() ; i++){
				
				if(i == 0){
					newal.add(ato.getColNum(al.get(i).trim()).trim());
					remember  = Integer.parseInt(ato.getColNum(al.get(i).trim()).trim());
				}

				
			}
			newht.put(keyset.get(index), newal);
			newal = new ArrayList<String>();
		}
		
		
		return newht;
		
	}

}
